﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Specialized;
using Microsoft.DirectX.DirectSound;

namespace MDXTest
{
    class MicManager
    {
        static MicManager instance;
        
        private Capture capture;
        private CaptureBuffer buffer;
        private Notify notify;
        private int rate;
        private short channels;
        private short rez;
        private int cps;
        private double bfsec;

        private MicManager()
        {
        }

        public static MicManager getInstance()
        {
            if (instance == null)
            {
                instance = new MicManager();
            }
            return instance;
        }

        public CaptureBuffer CaptureBuffer
        {
            get
            {
                if (this.buffer == null)
                {
                    throw new InvalidOperationException("Invalid Access : MicManager is not initialized");
                }
                return this.buffer;
            }
        }

        public Capture Capture
        {
            get
            {
                if (this.capture == null)
                {
                    throw new InvalidOperationException("Invalid Access : MicManager is not initialized"); 
                }
                return this.capture;
            }
        }

        public Notify Notify
        {
            get
            {
                return this.notify;
            }
        }

        public static WaveFormat getWaveFormat(int rate = 44100, short channels = 1, short rez = 16)
        {

            WaveFormat format = new WaveFormat();
            format.FormatTag = WaveFormatTag.Pcm;
            format.SamplesPerSecond = rate;
			format.Channels = channels;
            format.BitsPerSample = rez;
            format.BlockAlign = (short)(format.Channels * format.BitsPerSample / 8);
            format.AverageBytesPerSecond = format.SamplesPerSecond * format.BlockAlign;
            return format;
		}

        public void Initialize(double bfsec = 1, int rate = 44100, short channels = 1, short rez = 16)
        {
            this.bfsec = bfsec;
            this.rate = rate;
            this.channels = channels;
            this.rez = rez;

            this.capture = new Capture();
            CaptureBufferDescription desc = new CaptureBufferDescription();
            desc.ControlEffects = false;
            desc.WaveMapped = true;
            desc.Format = getWaveFormat(rate, channels, rez);
            desc.BufferBytes = (int)(desc.Format.AverageBytesPerSecond * bfsec);
            
            this.buffer = new CaptureBuffer(desc, capture); 
        }

        public void StartCapture(int cps, AutoResetEvent captureEvent)
        {
            this.cps = cps;
            BufferPositionNotify[] list = new BufferPositionNotify[cps];
            for (int i = 0; i < cps; i++)
            {
                list[i] = new BufferPositionNotify();
                list[i].EventNotifyHandle = captureEvent.Handle;
                list[i].Offset = this.CaptureBuffer.Format.AverageBytesPerSecond * (i + 1) / this.cps - 1;
            }

            Notify notify = new Notify(this.CaptureBuffer);
            notify.SetNotificationPositions(list);

            this.CaptureBuffer.Start(true);
        }

        public void StopCapture()
        {
            this.CaptureBuffer.Stop();
        }

        public void DisposeCapture()
        {
            this.CaptureBuffer.Dispose();
            this.Capture.Dispose();
        }
    }
}
